namespace EncoderCmdlet
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Management.Automation;
    using System.Reflection;
    using Microsoft.Expression.Encoder;
    using Microsoft.Expression.Encoder.Templates;
    using System.Diagnostics;

    /// <summary>
    /// Cmdlet to encode one or more video files
    /// </summary>
    [Cmdlet("Convert", "Media", SupportsShouldProcess = true)]
    public class ConvertMedia : PSCmdlet
    {
        #region member variables
        /// <summary>
        /// member variable holding current template
        /// </summary>
        private Template template;

        /// <summary>
        /// member variable holding list of files to batch encode
        /// </summary>
        private List<string> inputBatch = new List<string>();
        #endregion

        #region Parameters
        /// <summary>
        /// Parameter that extracts FullName from the input stream which is the path property on FileInfo
        /// </summary>
        [Alias("FullName")]
        [Parameter(ParameterSetName = "Objects", Mandatory = false, ValueFromPipelineByPropertyName = true)]
        [ValidateNotNullOrEmpty]
        public string Input
        {
            get;
            set;
        }

        /// <summary>
        /// Parameter representing the output directory where the encoded files will go
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "Output diretory for the job")]
        [ValidateNotNullOrEmpty]
        public string Output
        {
            get;
            set;
        }

        /// <summary>
        /// Parameter setting the Title metadata tag
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "Set Title metadata")]
        [ValidateNotNullOrEmpty]
        public string Title
        {
            get;
            set;
        }

        /// <summary>
        /// Parameter setting the Description metadata tag
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "Set Description metadata")]
        [ValidateNotNullOrEmpty]
        public string Description
        {
            get;
            set;
        }

        /// <summary>
        /// Parameter representing the full path to an Expression Encoder job file to be loaded
        /// </summary>
        [Parameter(ParameterSetName = "JobFile", Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "Path to an Expression Encoder job file")]
        [ValidateNotNullOrEmpty]
        public string JobFile
        {
            get;
            set;
        }

        /// <summary>
        /// Filename of preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        public string PresetFileName
        {
            get;
            set;
        }

        /// <summary>
        /// Pass in the preset XML
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        public string PresetString
        {
            get;
            set;
        }

        /// <summary>
        /// Path to leader file
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        public string LeaderFileName
        {
            get;
            set;
        }

        /// <summary>
        /// Path to leader file
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        public string TrailerFileName
        {
            get;
            set;
        }

        /// <summary>
        /// Path to leader file
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter ThumbsForMarkers
        {
            get;
            set;
        }


        #endregion

        #region Parameter switches for presets

        /////////////////////////////////////////////////////////////////////

        /// <summary>
        /// H264MotionThumbnailVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264MotionThumbnailVBR
        {
            get;
            set;
        }

        /// <summary>
        /// H264ScreenEncodingVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264ScreenEncodingVBR
        {
            get;
            set;
        }

        /// <summary>
        /// H264VimeoHD Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264VimeoHD
        {
            get;
            set;
        }

        /// <summary>
        /// H264VimeoSD Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264VimeoSD
        {
            get;
            set;
        }

        /// <summary>
        /// H264YouTubeHD Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264YouTubeHD
        {
            get;
            set;
        }

        /// <summary>
        /// H264YouTubeSD Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264YouTubeSD
        {
            get;
            set;
        }

        /// <summary>
        /// H264Zune2 Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264Zune2
        {
            get;
            set;
        }

        /// <summary>
        /// H264Zune2AVDockPlayback Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264Zune2AVDockPlayback
        {
            get;
            set;
        }

        /// <summary>
        /// H264ZuneHD Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264ZuneHD
        {
            get;
            set;
        }

        /// <summary>
        /// H264ZuneHDAVDockPlayback Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter H264ZuneHDAVDockPlayback
        {
            get;
            set;
        }

        /// <summary>
        /// VC1256kDSLCBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1256kDSLCBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1256kDSLVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1256kDSLVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1512kDSLCBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1512kDSLCBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1512kDSLVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1512kDSLVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1BroadbandCBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1BroadbandCBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1BroadbandVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1BroadbandVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1HD1080pVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1HD1080pVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1HD720pVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1HD720pVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1HighSpeedBroadbandCBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1HighSpeedBroadbandCBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1HighSpeedBroadbandVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1HighSpeedBroadbandVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1IISSmoothStreaming720pCBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1IISSmoothStreaming720pCBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1IISSmoothStreamingHD1080pVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1IISSmoothStreamingHD1080pVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1IISSmoothStreamingHD720pVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1IISSmoothStreamingHD720pVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1IISSmoothStreamingScreenEncodingVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1IISSmoothStreamingScreenEncodingVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1IISSmoothStreamingSD480pVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1IISSmoothStreamingSD480pVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1MotionThumbnailVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1MotionThumbnailVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1ScreenEncodingVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1ScreenEncodingVBR
        {
            get;
            set;
        }

        /// <summary>
        /// VC1WindowsMobile Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [PresetSwitch()]
        [ValidateNotNullOrEmpty]
        public SwitchParameter VC1WindowsMobile
        {
            get;
            set;
        }

        /// <summary>
        /// VC1XBox360 Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1XBox360
        {
            get;
            set;
        }

        /// <summary>
        /// VC1Zune1 Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1Zune1
        {
            get;
            set;
        }

        /// <summary>
        /// VC1Zune2 Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1Zune2
        {
            get;
            set;
        }

        /// <summary>
        /// VC1Zune2AVDockPlayback Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1Zune2AVDockPlayback
        {
            get;
            set;
        }

        /// <summary>
        /// VC1ZuneHD Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1ZuneHD
        {
            get;
            set;
        }

        /// <summary>
        /// VC1ZuneHDAVDockPlayback Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter VC1ZuneHDAVDockPlayback
        {
            get;
            set;
        }

        /// <summary>
        /// WMABestQualityVBR Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter WMABestQualityVBR
        {
            get;
            set;
        }

        /// <summary>
        /// WMAGoodQualityAudio Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter WMAGoodQualityAudio
        {
            get;
            set;
        }

        /// <summary>
        /// WMAHighQualityAudio Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter WMAHighQualityAudio
        {
            get;
            set;
        }

        /// <summary>
        /// WMALossless51Audio Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter WMALossless51Audio
        {
            get;
            set;
        }

        /// <summary>
        /// WMALowQualityAudio Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter WMALowQualityAudio
        {
            get;
            set;
        }

        /// <summary>
        /// WMAVoiceAudio Preset
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [PresetSwitch()]
        public SwitchParameter WMAVoiceAudio
        {
            get;
            set;
        }
        #endregion

        #region Parameter switches for templates
        /// <summary>
        /// Archetype Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("Archetype")]
        public SwitchParameter TemplateArchetype
        {
            get;
            set;
        }

        /// <summary>
        /// BlackGlass Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("BlackGlass")]
        public SwitchParameter TemplateBlackGlass
        {
            get;
            set;
        }

        /// <summary>
        /// Chrome Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("Chrome")]
        public SwitchParameter TemplateChrome
        {
            get;
            set;
        }

        /// <summary>
        /// Corporate Silver Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("CorporateSilver")]
        public SwitchParameter TemplateCorporateSilver
        {
            get;
            set;
        }

        /// <summary>
        /// Clean Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("Clean")]
        public SwitchParameter TemplateClean
        {
            get;
            set;
        }

        /// <summary>
        /// Expression Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("Expression")]
        public SwitchParameter TemplateExpression
        {
            get;
            set;
        }

        /// <summary>
        /// FrostedGallery Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("FrostedGallery")]
        public SwitchParameter TemplateFrostedGallery
        {
            get;
            set;
        }

        /// <summary>
        /// GoldenAudio Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("GoldenAudio")]
        public SwitchParameter TemplateGoldenAudio
        {
            get;
            set;
        }

        /// <summary>
        /// Jukebox Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("Jukebox")]
        public SwitchParameter TemplateJukebox
        {
            get;
            set;
        }

        /// <summary>
        /// Popup Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("Popup")]
        public SwitchParameter TemplatePopup
        {
            get;
            set;
        }

        /// <summary>
        /// QuikSilver Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("QuikSilver")]
        public SwitchParameter TemplateQuikSilver
        {
            get;
            set;
        }

        /// <summary>
        /// Reflection Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("Reflection")]
        public SwitchParameter TemplateReflection
        {
            get;
            set;
        }

        /// <summary>
        /// SL3AudioOnly Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("SL3AudioOnly")]
        public SwitchParameter TemplateSL3AudioOnly
        {
            get;
            set;
        }

        /// <summary>
        /// SL3Diagnostic Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("SL3Diagnostic")]
        public SwitchParameter TemplateSL3Diagnostic
        {
            get;
            set;
        }

        /// <summary>
        /// SL3Gallery Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]

        [ValidateNotNullOrEmpty]
        [TemplateSwitch("SL3Gallery")]
        public SwitchParameter TemplateSL3Gallery
        {
            get;
            set;
        }

        /// <summary>
        /// SL3Standard Template
        /// </summary>
        [Parameter(ParameterSetName = "Objects", Mandatory = false)]
        [ValidateNotNullOrEmpty]
        [TemplateSwitch("SL3Standard")]
        public SwitchParameter TemplateSL3Standard
        {
            get;
            set;
        }

        #endregion

        #region job configuration
        /// <summary>
        /// Configures template property on job.
        /// </summary>
        /// <param name="template">template instance</param>
        /// <param name="job">job instance</param>
        static void ConfigureTemplate(Template template, Microsoft.Expression.Encoder.Job job)
        {
            if (template != null)
            {
                job.Template = template;
            }
        }

        /// <summary>
        /// Configure metadata on job
        /// </summary>
        /// <param name="job">job instance</param>
        void ConfigureMetadata(Microsoft.Expression.Encoder.Job job)
        {
            foreach (MediaItem item in job.MediaItems)
            {
                if (!string.IsNullOrEmpty(this.Title))
                {
                    item.Metadata["Title"] = this.Title;
                }

                if (!string.IsNullOrEmpty(this.Description))
                {
                    item.Metadata["Description"] = this.Title;
                }
            }
        }

        /// <summary>
        /// Configure output directory on a job instance.
        /// </summary>
        /// <param name="job">job instance</param>
        void ConfigureOutputDirectory(Microsoft.Expression.Encoder.Job job)
        {
            string outDir = string.Empty;

            if (!String.IsNullOrEmpty(this.Output))
            {
                outDir = this.Output;
            }
            else
            {
                outDir = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Expression\Expression Encoder\Output";
            }

            // since the template contains multiple files, we will turn on subfoldering
            //if (this.template != null)
            {
                job.CreateSubfolder = true;
            }
            //else
            //{
            //    job.CreateSubfolder = false;
            //}

            job.OutputDirectory = outDir;
        }
        #endregion

        /// <summary>
        /// Override BeginProcessing to initialize session variables
        /// </summary>
        protected override void BeginProcessing()
        {
            base.BeginProcessing();
            this.inputBatch.Clear();
            this.template = this.ProcessTemplateSwitches();
            base.WriteProgress(new ProgressRecord(0, "Starting", "Starting") { RecordType = ProgressRecordType.Processing });
        }

        /// <summary>
        /// Override EndProcessing.  Process any items that have been batched
        /// </summary>
        protected override void EndProcessing()
        {
            if (this.inputBatch.Count > 0)
            {
                this.EncodeItemsWithTemplate(this.inputBatch, this.template);
            }

            base.EndProcessing();
            base.WriteProgress(new ProgressRecord(0, "Complete", "Complete") { RecordType = ProgressRecordType.Completed });
        }

        /// <summary>
        /// Main entrypoint for cmdlet.
        /// </summary>
        protected override void ProcessRecord()
        {
            if (ParameterSetName == "JobFile")
            {
                WriteVerbose(string.Format(CultureInfo.CurrentCulture, "Beginning job file {0}", this.JobFile));
                this.EncodeJob(this.JobFile);
            }
            else if (ParameterSetName == "Objects" && (this.Input != null && this.Input.Length > 0))
            {
                if (this.template != null)
                {
                    this.inputBatch.Add(this.Input);
                }
                else
                {
                    this.EncodeItem(this.Input);
                }
            }
            else
            {
                WriteWarning("No inputs");
            }
        }

        /// <summary>
        /// Encode a job based on a job file
        /// </summary>
        /// <param name="jobPath">path to job file</param>
        void EncodeJob(string jobPath)
        {
            using (Microsoft.Expression.Encoder.Job job = Microsoft.Expression.Encoder.Job.LoadJob(jobPath))
            {
                job.EncodeProgress += new EventHandler<Microsoft.Expression.Encoder.EncodeProgressEventArgs>(this.EncodeProgress);

                job.Encode();
            }
        }

        /// <summary>
        /// Encode a job based on a number of input files and a template
        /// </summary>
        /// <param name="inputPaths">array of paths to input files</param>
        /// <param name="templateObject">template instance</param>
        void EncodeItemsWithTemplate(IEnumerable<string> inputPaths, Template templateObject)
        {
            using (Microsoft.Expression.Encoder.Job job = new Microsoft.Expression.Encoder.Job())
            {
                foreach (string name in inputPaths)
                {
                    job.MediaItems.Add(new MediaItem(name) { ThumbnailMode = templateObject != null ? ThumbnailMode.BestFrame : ThumbnailMode.None });
                }

                string[] presets = GetPresentSwitchesWithAttribute<PresetSwitch>(string.Empty);

                // Since we are encoding with a template, we only want a single preset to apply to each item
                if (presets.Length > 1)
                {
                    this.ThrowTerminatingError(new ErrorRecord(null, string.Empty, ErrorCategory.InvalidArgument, null));
                }

                Preset preset = GetPropertyValue(presets[0], typeof(Presets)) as Preset;

                foreach (MediaItem mediaItem in job.MediaItems)
                {
                    mediaItem.ApplyPreset(preset);
                }

                this.ConfigureOutputDirectory(job);

                this.ConfigureMetadata(job);

                ConfigureTemplate(templateObject, job);

                job.EncodeProgress += new EventHandler<Microsoft.Expression.Encoder.EncodeProgressEventArgs>(this.EncodeProgress);

                job.Encode();
            }
        }

        /// <summary>
        /// Encode items without a template applying multiple presets if present
        /// </summary>
        /// <param name="inputPath">array of paths to input files</param>
        void EncodeItem(string inputPath)
        {
            Microsoft.Expression.Encoder.Job job = null;

            try
            {
                WriteVerbose(string.Format(CultureInfo.CurrentCulture, "Beginning {0}", inputPath));

                job = new Microsoft.Expression.Encoder.Job();

                this.ProcessPresetSwitches(inputPath, job);

                // if no presets were selected, add the input which will be processed with default settings
                if (job.MediaItems.Count == 0)
                {
                    MediaItem mediaItem = new MediaItem(inputPath);
                    job.MediaItems.Add(mediaItem);
                }

                if (!string.IsNullOrEmpty(this.PresetFileName))
                {
                    try
                    {
                        job.ApplyPreset(this.PresetFileName);
                    }
                    catch (Exception ex)
                    {
                        Debug.Write(ex);
                    }
                }

                if (!string.IsNullOrEmpty(this.PresetString))
                {
                    string presetTempPath = Path.GetTempFileName();
                    File.WriteAllText(presetTempPath, PresetString, new System.Text.UnicodeEncoding());

                    try
                    {
                        job.ApplyPreset(Preset.FromFile(presetTempPath));
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                    }

                    File.Delete(presetTempPath);
                }

                if (!string.IsNullOrEmpty(LeaderFileName))
                {
                    try
                    {
                        job.MediaItems[0].Sources.Insert(0, new Source(LeaderFileName));

                        switch (Path.GetExtension(LeaderFileName).ToLower())
                        {
                            case ".jpg":
                            case ".png":
                                job.MediaItems[0].Sources[0].Clips[0].EndTime = new TimeSpan(0, 0, 3);
                                break;
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                    }
                }

                if (!string.IsNullOrEmpty(TrailerFileName))
                {
                    try
                    {
                        job.MediaItems[0].Sources.Add(new Source(TrailerFileName));

                        switch (Path.GetExtension(LeaderFileName).ToLower())
                        {
                            case ".jpg":
                            case ".png":
                                job.MediaItems[0].Sources[job.MediaItems[0].Sources.Count - 1].Clips[0].EndTime = new TimeSpan(0, 0, 3);
                                break;
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                    }
                }

                this.ConfigureMetadata(job);

                if (ThumbsForMarkers.IsPresent)
                {
                    foreach (var jobitem in job.MediaItems)
                    {
                        foreach (var item in jobitem.Markers)
                        {
                            item.GenerateThumbnail = true;
                        }
                    }
                }

                this.ConfigureOutputDirectory(job);

                job.EncodeProgress += new EventHandler<Microsoft.Expression.Encoder.EncodeProgressEventArgs>(this.EncodeProgress);

                job.Encode();

                foreach (MediaItem mediaItem in job.MediaItems)
                {
                    FileInfo fi = new FileInfo(mediaItem.ActualOutputFileFullPath);
                    DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(mediaItem.ActualOutputFileFullPath));
                    WriteObject(di);
                }
            }
            catch (Exception e) // because we wan't to continue to the next item
            {
                this.WriteError(new ErrorRecord(e, string.Empty, ErrorCategory.NotSpecified, null));
            }
            finally
            {
                job.Dispose();
            }
        }

        #region switch processing
        /// <summary>
        /// Use reflection to determine which template switches are present and return chosen template
        /// </summary>
        /// <returns>Template instance</returns>
        Template ProcessTemplateSwitches()
        {
            string[] templates = GetPresentSwitchesWithAttribute<TemplateSwitch>("PropertyName");

            if (templates.Length > 1)
            {
                this.WriteError(new ErrorRecord(null, "More than 1 template selected", ErrorCategory.InvalidArgument, this));
                this.EndProcessing();
            }

            if (templates.Length == 1)
            {
                return GetPropertyValue(templates[0], typeof(TemplateCollection)) as Template;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Use reflection to determine which preset switchas are present and add source for each and apply preset to source
        /// </summary>
        /// <param name="path">Source file path</param>
        /// <param name="job">job instance</param>
        void ProcessPresetSwitches(string path, Microsoft.Expression.Encoder.Job job)
        {
            string[] presets = GetPresentSwitchesWithAttribute<PresetSwitch>(string.Empty);

            foreach (var presetPropertyName in presets)
            {
                Preset preset = GetPropertyValue(presetPropertyName, typeof(Presets)) as Preset;

                if (preset != null)
                {
                    Microsoft.Expression.Encoder.MediaItem item = new Microsoft.Expression.Encoder.MediaItem(path);

                    item.OutputFileName = string.Format(CultureInfo.CurrentCulture, "{{Original file name}} {0}.{{Default extension}}", presetPropertyName);

                    job.MediaItems.Add(item);

                    item.ApplyPreset(preset);
                }
            }
        }
        #endregion

        #region reflection
        /// <summary>
        /// For a givern attribute type, return switches that are decorated with that attribute and that the user has supplied
        /// </summary>
        /// <typeparam name="T">type of attribute to search for</typeparam>
        /// <param name="attributePropertyName">Optionally supply the name of a property on the attribute to return instead of the property name</param>
        /// <returns>string arrary containing property names</returns>
        string[] GetPresentSwitchesWithAttribute<T>(string attributePropertyName)
        {
            List<string> activeSwitches = new List<string>();
            Type encodedItemType = typeof(ConvertMedia);

            foreach (var info in encodedItemType.GetProperties())
            {
                string propertyName = info.Name;
                object[] attrs = info.GetCustomAttributes(typeof(T), false);
                if (attrs != null && attrs.Length == 1)
                {
                    T switchAttribute = (T)attrs[0];

                    object result = null;

                    result = encodedItemType.InvokeMember(propertyName, BindingFlags.GetProperty, null, this, null, CultureInfo.InvariantCulture);

                    if (result is SwitchParameter && ((SwitchParameter)result).IsPresent)
                    {
                        if (!string.IsNullOrEmpty(attributePropertyName))
                        {
                            activeSwitches.Add(typeof(T).InvokeMember(attributePropertyName, BindingFlags.GetProperty, null, switchAttribute, null, CultureInfo.InvariantCulture).ToString());
                        }
                        else
                        {
                            activeSwitches.Add(propertyName);
                        }
                    }
                }
            }

            return activeSwitches.ToArray();
        }

        /// <summary>
        /// Get static property value from a type
        /// </summary>
        /// <param name="propertyName">name of property</param>
        /// <param name="type">type to get property from</param>
        /// <returns>property value</returns>
        static object GetPropertyValue(string propertyName, Type type)
        {
            PropertyInfo[] infos = type.GetProperties();

            foreach (PropertyInfo pi in infos)
            {
                if (string.CompareOrdinal(pi.Name, propertyName) == 0)
                {
                    return type.InvokeMember(pi.Name, BindingFlags.GetProperty, null, null, null, CultureInfo.InvariantCulture);
                }
            }

            return null;
        }
        #endregion

        #region event handlers
        /// <summary>
        /// Event handler for job progress
        /// </summary>
        /// <param name="sender">object instance that raised event</param>
        /// <param name="e">event arguments</param>
        void EncodeProgress(object sender, Microsoft.Expression.Encoder.EncodeProgressEventArgs e)
        {
            if (this.Stopping)
            {
                e.Cancel = true;
            }
            else
            {
                string progress = string.Format(
                    CultureInfo.CurrentCulture,
                    "Encoding {0} {1} % Pass {2} of {3}",
                    e.CurrentItem.ActualOutputFileName,
                    Convert.ToInt32(e.Progress).ToString(CultureInfo.CurrentUICulture),
                    e.CurrentPass,
                    e.TotalPasses);

                ProgressRecord record = new ProgressRecord(0, "Encoding", progress);
                record.PercentComplete = Convert.ToInt32(e.Progress);
                WriteProgress(record);
            }
        }
        #endregion
    }
}
